#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Auto-sklearn自定义分类器扩展示例
Custom Classification Component Extension Example

本示例演示如何创建自定义的MLP分类器组件，并将其集成到Auto-sklearn
框架中。通过完整的开发流程，学习组件接口设计、超参数空间定义和
性能评估方法。

作者: AutoML学习团队
日期: 2024-07-13
"""

import os
import time
import warnings
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime
from pprint import pprint
from typing import Optional

# Auto-sklearn和ConfigSpace相关导入
from ConfigSpace.configuration_space import ConfigurationSpace
from ConfigSpace.hyperparameters import (
    CategoricalHyperparameter,
    UniformIntegerHyperparameter,
    UniformFloatHyperparameter,
)

import sklearn.metrics
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.inspection import permutation_importance

# Auto-sklearn相关导入
from autosklearn.askl_typing import FEAT_TYPE_TYPE
import autosklearn.classification
import autosklearn.pipeline.components.classification
from autosklearn.pipeline.components.base import AutoSklearnClassificationAlgorithm
from autosklearn.pipeline.constants import (
    DENSE,
    SIGNED_DATA,
    UNSIGNED_DATA,
    PREDICTIONS,
)

# 忽略警告信息
warnings.filterwarnings('ignore')

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False


class CustomMLPClassifier(AutoSklearnClassificationAlgorithm):
    """
    自定义多层感知机分类器
    
    扩展Auto-sklearn的分类算法基类，提供灵活的神经网络配置
    和针对医疗数据优化的超参数搜索空间。
    
    特性:
    - 支持可变的网络深度和宽度
    - 多种激活函数选择
    - 自适应正则化策略
    - 医疗AI优化的默认配置
    """
    
    def __init__(self, hidden_layer_depth, num_nodes_per_layer, 
                 activation, alpha, solver, random_state=None):
        """
        初始化自定义MLP分类器
        
        参数:
            hidden_layer_depth (int): 隐藏层数量 [1-4]
            num_nodes_per_layer (int): 每层节点数 [32-256]
            activation (str): 激活函数 ['relu', 'tanh', 'logistic']
            alpha (float): L2正则化系数 [1e-5, 1e-1]
            solver (str): 优化算法 ['adam', 'lbfgs', 'sgd']
            random_state (int): 随机种子
        """
        self.hidden_layer_depth = hidden_layer_depth
        self.num_nodes_per_layer = num_nodes_per_layer
        self.activation = activation
        self.alpha = alpha
        self.solver = solver
        self.random_state = random_state
        self.estimator = None
        
        print(f"🧠 初始化自定义MLP分类器")
        print(f"   隐藏层数: {hidden_layer_depth}")
        print(f"   每层节点数: {num_nodes_per_layer}")
        print(f"   激活函数: {activation}")
        print(f"   正则化系数: {alpha}")
        print(f"   优化器: {solver}")
    
    def fit(self, X, y):
        """
        训练MLP分类器
        
        参数:
            X (array-like): 训练特征矩阵
            y (array-like): 训练标签向量
            
        返回:
            self: 训练后的分类器实例
        """
        print(f"🔧 开始训练自定义MLP分类器")
        
        # 参数类型转换和验证
        self.num_nodes_per_layer = int(self.num_nodes_per_layer)
        self.hidden_layer_depth = int(self.hidden_layer_depth)
        self.alpha = float(self.alpha)
        
        # 构建隐藏层架构
        hidden_layer_sizes = tuple(
            self.num_nodes_per_layer 
            for _ in range(self.hidden_layer_depth)
        )
        
        print(f"   网络架构: 输入层({X.shape[1]}) -> {hidden_layer_sizes} -> 输出层(2)")
        
        # 创建sklearn MLP分类器
        from sklearn.neural_network import MLPClassifier
        
        self.estimator = MLPClassifier(
            hidden_layer_sizes=hidden_layer_sizes,
            activation=self.activation,
            alpha=self.alpha,
            solver=self.solver,
            random_state=self.random_state,
            max_iter=1000,  # 增加最大迭代次数
            learning_rate_init=0.001,  # 初始学习率
            early_stopping=True,  # 启用早停
            validation_fraction=0.1,  # 验证集比例
            n_iter_no_change=10,  # 早停耐心值
            tol=1e-4  # 收敛容忍度
        )
        
        # 记录训练开始时间
        start_time = time.time()
        
        # 训练模型
        self.estimator.fit(X, y)
        
        # 记录训练结果
        training_time = time.time() - start_time
        print(f"   训练完成，用时: {training_time:.2f}秒")
        print(f"   迭代次数: {self.estimator.n_iter_}")
        print(f"   最终损失: {self.estimator.loss_:.4f}")
        
        return self
    
    def predict(self, X):
        """
        预测类别标签
        
        参数:
            X (array-like): 测试特征矩阵
            
        返回:
            array: 预测的类别标签
        """
        if self.estimator is None:
            raise NotImplementedError("模型尚未训练，请先调用fit方法")
        return self.estimator.predict(X)
    
    def predict_proba(self, X):
        """
        预测类别概率
        
        参数:
            X (array-like): 测试特征矩阵
            
        返回:
            array: 各类别的预测概率矩阵
        """
        if self.estimator is None:
            raise NotImplementedError("模型尚未训练，请先调用fit方法")
        return self.estimator.predict_proba(X)
    
    def get_feature_importance(self, X, y):
        """
        计算特征重要性(用于医疗AI的可解释性)
        
        参数:
            X (array-like): 特征矩阵
            y (array-like): 标签向量
            
        返回:
            array: 特征重要性分数
        """
        if self.estimator is None:
            raise NotImplementedError("模型尚未训练")
            
        # 使用排列重要性计算特征重要性
        perm_importance = permutation_importance(
            self.estimator, X, y,
            scoring='accuracy',
            n_repeats=10,
            random_state=self.random_state
        )
        
        return perm_importance.importances_mean
    
    @staticmethod
    def get_properties(dataset_properties=None):
        """
        定义分类器组件属性
        
        返回组件的能力描述和数据类型支持信息，用于Auto-sklearn
        的组件选择和验证流程。
        
        返回:
            dict: 组件属性字典
        """
        return {
            'shortname': 'CustomMLP',
            'name': 'Custom Multi-Layer Perceptron Classifier',
            'handles_regression': False,
            'handles_classification': True,
            'handles_multiclass': True,
            'handles_multilabel': False,
            'handles_multioutput': False,
            'is_deterministic': False,
            # 支持的输入数据类型
            'input': [DENSE, SIGNED_DATA, UNSIGNED_DATA],
            # 输出类型
            'output': [PREDICTIONS]
        }
    
    @staticmethod
    def get_hyperparameter_search_space(feat_type: Optional[FEAT_TYPE_TYPE] = None, 
                                      dataset_properties=None):
        """
        定义超参数搜索空间
        
        基于医疗AI应用的需求和计算资源约束，定义合理的超参数
        搜索范围，支持Bayesian优化的高效搜索。
        
        参数:
            feat_type: 特征类型信息
            dataset_properties: 数据集属性
            
        返回:
            ConfigurationSpace: 配置空间对象
        """
        cs = ConfigurationSpace()
        
        # 网络深度: 针对中等规模数据集的合理范围
        hidden_layer_depth = UniformIntegerHyperparameter(
            name='hidden_layer_depth',
            lower=1, upper=3,  # 限制深度避免过拟合
            default_value=2,
            meta={'description': '隐藏层数量，影响模型表达能力'}
        )
        
        # 网络宽度: 根据特征数量和数据规模设计
        num_nodes_per_layer = UniformIntegerHyperparameter(
            name='num_nodes_per_layer',
            lower=32, upper=128,  # 适中的网络宽度
            default_value=64,
            meta={'description': '每层神经元数量，影响学习容量'}
        )
        
        # 激活函数: 常用的非线性激活函数
        activation = CategoricalHyperparameter(
            name='activation',
            choices=['relu', 'tanh', 'logistic'],
            default_value='relu',
            meta={'description': '激活函数类型，影响非线性建模能力'}
        )
        
        # 正则化强度: 对数尺度搜索
        alpha = UniformFloatHyperparameter(
            name='alpha',
            lower=1e-5, upper=1e-2,  # 适合医疗数据的正则化范围
            default_value=1e-4,
            log=True,
            meta={'description': 'L2正则化系数，防止过拟合'}
        )
        
        # 优化算法: 适合不同数据规模的优化器
        solver = CategoricalHyperparameter(
            name='solver',
            choices=['adam', 'lbfgs'],  # 排除SGD简化搜索空间
            default_value='adam',
            meta={'description': '权重优化算法'}
        )
        
        # 添加超参数到配置空间
        cs.add_hyperparameters([
            hidden_layer_depth,
            num_nodes_per_layer,
            activation,
            alpha,
            solver
        ])
        
        # 可以添加条件依赖关系(高级用法)
        # 例如: learning_rate只在solver='sgd'时有效
        
        return cs


def load_and_preprocess_data():
    """
    加载和预处理乳腺癌数据集
    
    返回:
        tuple: (X_train, X_test, y_train, y_test, feature_names)
    """
    print("📊 加载和预处理数据")
    
    # 加载乳腺癌数据集
    data = load_breast_cancer()
    X, y = data.data, data.target
    feature_names = data.feature_names
    
    print(f"   数据集形状: {X.shape}")
    print(f"   特征数量: {X.shape[1]}")
    print(f"   样本数量: {X.shape[0]}")
    print(f"   类别分布: 良性={np.sum(y==1)}, 恶性={np.sum(y==0)}")
    
    # 数据集分割
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.3, random_state=42, stratify=y
    )
    
    # 特征标准化(MLP对特征尺度敏感)
    scaler = StandardScaler()
    X_train_scaled = scaler.fit_transform(X_train)
    X_test_scaled = scaler.transform(X_test)
    
    print(f"   训练集: {X_train_scaled.shape}")
    print(f"   测试集: {X_test_scaled.shape}")
    
    return X_train_scaled, X_test_scaled, y_train, y_test, feature_names


def test_custom_component():
    """
    测试自定义分类器组件的基本功能
    """
    print("\n🧪 测试自定义MLP分类器组件")
    
    # 加载数据
    X_train, X_test, y_train, y_test, feature_names = load_and_preprocess_data()
    
    # 创建自定义分类器实例
    custom_mlp = CustomMLPClassifier(
        hidden_layer_depth=2,
        num_nodes_per_layer=64,
        activation='relu',
        alpha=0.0001,
        solver='adam',
        random_state=42
    )
    
    # 训练模型
    custom_mlp.fit(X_train, y_train)
    
    # 进行预测
    y_pred = custom_mlp.predict(X_test)
    y_proba = custom_mlp.predict_proba(X_test)
    
    # 评估性能
    accuracy = sklearn.metrics.accuracy_score(y_test, y_pred)
    auc_score = sklearn.metrics.roc_auc_score(y_test, y_proba[:, 1])
    
    print(f"\n📈 自定义MLP分类器性能:")
    print(f"   准确率: {accuracy:.4f}")
    print(f"   AUC分数: {auc_score:.4f}")
    
    # 详细分类报告
    print(f"\n📋 详细分类报告:")
    print(classification_report(y_test, y_pred, target_names=['恶性', '良性']))
    
    # 计算特征重要性
    feature_importance = custom_mlp.get_feature_importance(X_test, y_test)
    
    # 显示最重要的特征
    top_features_idx = np.argsort(feature_importance)[-10:]
    print(f"\n🔍 最重要的10个特征:")
    for i, idx in enumerate(reversed(top_features_idx)):
        print(f"   {i+1:2d}. {feature_names[idx]}: {feature_importance[idx]:.4f}")
    
    return custom_mlp, X_train, X_test, y_train, y_test


def register_and_test_automl():
    """
    注册自定义组件到Auto-sklearn并测试AutoML功能
    """
    print("\n🔧 注册自定义组件到Auto-sklearn")
    
    # 注册自定义分类器
    autosklearn.pipeline.components.classification.add_classifier(CustomMLPClassifier)
    
    # 验证注册成功
    available_classifiers = autosklearn.pipeline.components.classification._classifiers
    if 'CustomMLPClassifier' in available_classifiers:
        print("✅ 自定义MLP分类器注册成功")
    else:
        print("❌ 自定义MLP分类器注册失败")
        return None
    
    # 显示超参数搜索空间
    cs = CustomMLPClassifier.get_hyperparameter_search_space()
    print(f"\n🎛️ 超参数搜索空间:")
    print(cs)
    
    # 加载数据
    X_train, X_test, y_train, y_test, feature_names = load_and_preprocess_data()
    
    print(f"\n🤖 创建Auto-sklearn分类器(仅使用自定义组件)")
    
    # 创建Auto-sklearn分类器，仅使用自定义组件
    automl_clf = autosklearn.classification.AutoSklearnClassifier(
        time_left_for_this_task=60,  # 1分钟训练时间
        per_run_time_limit=20,       # 每次运行最多20秒
        include={'classifier': ['CustomMLPClassifier']},  # 仅使用自定义分类器
        initial_configurations_via_metalearning=0,  # 禁用元学习加速演示
        smac_scenario_args={'runcount_limit': 10},   # 限制评估次数
        memory_limit=3072,  # 内存限制
        seed=42
    )
    
    # 训练AutoML模型
    print("🚀 开始AutoML训练...")
    start_time = time.time()
    
    automl_clf.fit(X_train, y_train)
    
    training_time = time.time() - start_time
    print(f"✅ AutoML训练完成，用时: {training_time:.2f}秒")
    
    # 进行预测和评估
    y_pred_automl = automl_clf.predict(X_test)
    y_proba_automl = automl_clf.predict_proba(X_test)
    
    # 计算性能指标
    accuracy_automl = sklearn.metrics.accuracy_score(y_test, y_pred_automl)
    auc_automl = sklearn.metrics.roc_auc_score(y_test, y_proba_automl[:, 1])
    
    print(f"\n📊 AutoML性能结果:")
    print(f"   准确率: {accuracy_automl:.4f}")
    print(f"   AUC分数: {auc_automl:.4f}")
    
    # 显示最佳模型配置
    print(f"\n🏆 最佳模型配置:")
    pprint(automl_clf.show_models(), indent=4)
    
    # 统计信息
    print(f"\n📈 AutoML统计信息:")
    print(f"   评估的配置数量: {len(automl_clf.cv_results_)}")
    print(f"   最佳配置得分: {max(automl_clf.cv_results_['mean_test_score']):.4f}")
    
    return automl_clf, X_train, X_test, y_train, y_test


def create_performance_visualization(custom_mlp, automl_clf, X_test, y_test):
    """
    创建性能可视化图表
    
    参数:
        custom_mlp: 单独训练的自定义分类器
        automl_clf: AutoML训练的分类器
        X_test: 测试特征
        y_test: 测试标签
    """
    print("\n📊 创建性能可视化")
    
    # 获取预测概率
    y_proba_custom = custom_mlp.predict_proba(X_test)[:, 1]
    y_proba_automl = automl_clf.predict_proba(X_test)[:, 1]
    
    # 创建图表
    fig, axes = plt.subplots(2, 2, figsize=(15, 12))
    fig.suptitle('自定义MLP分类器 vs AutoML性能对比', fontsize=16, fontweight='bold')
    
    # 1. ROC曲线对比
    from sklearn.metrics import roc_curve, auc
    
    fpr_custom, tpr_custom, _ = roc_curve(y_test, y_proba_custom)
    fpr_automl, tpr_automl, _ = roc_curve(y_test, y_proba_automl)
    
    auc_custom = auc(fpr_custom, tpr_custom)
    auc_automl = auc(fpr_automl, tpr_automl)
    
    axes[0, 0].plot(fpr_custom, tpr_custom, 'b-', label=f'自定义MLP (AUC={auc_custom:.3f})')
    axes[0, 0].plot(fpr_automl, tpr_automl, 'r-', label=f'AutoML (AUC={auc_automl:.3f})')
    axes[0, 0].plot([0, 1], [0, 1], 'k--', alpha=0.5)
    axes[0, 0].set_xlabel('假正率 (FPR)')
    axes[0, 0].set_ylabel('真正率 (TPR)')
    axes[0, 0].set_title('ROC曲线对比')
    axes[0, 0].legend()
    axes[0, 0].grid(True, alpha=0.3)
    
    # 2. 预测概率分布
    axes[0, 1].hist(y_proba_custom[y_test==0], bins=20, alpha=0.5, label='恶性(自定义)', color='blue')
    axes[0, 1].hist(y_proba_custom[y_test==1], bins=20, alpha=0.5, label='良性(自定义)', color='lightblue')
    axes[0, 1].hist(y_proba_automl[y_test==0], bins=20, alpha=0.5, label='恶性(AutoML)', color='red')
    axes[0, 1].hist(y_proba_automl[y_test==1], bins=20, alpha=0.5, label='良性(AutoML)', color='pink')
    axes[0, 1].set_xlabel('预测概率')
    axes[0, 1].set_ylabel('样本数量')
    axes[0, 1].set_title('预测概率分布')
    axes[0, 1].legend()
    axes[0, 1].grid(True, alpha=0.3)
    
    # 3. 混淆矩阵对比
    from sklearn.metrics import confusion_matrix
    
    y_pred_custom = custom_mlp.predict(X_test)
    y_pred_automl = automl_clf.predict(X_test)
    
    cm_custom = confusion_matrix(y_test, y_pred_custom)
    cm_automl = confusion_matrix(y_test, y_pred_automl)
    
    # 自定义MLP混淆矩阵
    sns.heatmap(cm_custom, annot=True, fmt='d', cmap='Blues', 
                xticklabels=['恶性', '良性'], yticklabels=['恶性', '良性'],
                ax=axes[1, 0])
    axes[1, 0].set_title('自定义MLP - 混淆矩阵')
    axes[1, 0].set_xlabel('预测标签')
    axes[1, 0].set_ylabel('真实标签')
    
    # AutoML混淆矩阵
    sns.heatmap(cm_automl, annot=True, fmt='d', cmap='Reds',
                xticklabels=['恶性', '良性'], yticklabels=['恶性', '良性'],
                ax=axes[1, 1])
    axes[1, 1].set_title('AutoML - 混淆矩阵')
    axes[1, 1].set_xlabel('预测标签')
    axes[1, 1].set_ylabel('真实标签')
    
    plt.tight_layout()
    
    # 保存图表
    results_dir = "/root/code/ml/automl/examples/04_extending/01_classification_extension/results"
    os.makedirs(results_dir, exist_ok=True)
    plt.savefig(f"{results_dir}/performance_comparison.png", dpi=300, bbox_inches='tight')
    print(f"📁 性能对比图表已保存到: {results_dir}/performance_comparison.png")
    
    plt.show()


def create_medical_analysis_report(custom_mlp, X_test, y_test, feature_names):
    """
    创建医疗AI专用的分析报告
    
    参数:
        custom_mlp: 训练好的自定义分类器
        X_test: 测试特征
        y_test: 测试标签
        feature_names: 特征名称列表
    """
    print("\n🏥 生成医疗AI分析报告")
    
    # 计算医疗相关指标
    y_pred = custom_mlp.predict(X_test)
    y_proba = custom_mlp.predict_proba(X_test)
    
    from sklearn.metrics import precision_score, recall_score, f1_score
    
    # 医疗AI关键指标(以恶性为正类)
    sensitivity = recall_score(y_test, y_pred, pos_label=0)  # 恶性检出率
    specificity = precision_score(y_test, y_pred, pos_label=1)  # 良性识别率
    ppv = precision_score(y_test, y_pred, pos_label=0)  # 阳性预测值
    npv = recall_score(y_test, y_pred, pos_label=1)  # 阴性预测值
    
    print(f"🩺 医疗诊断性能指标:")
    print(f"   敏感性 (Sensitivity): {sensitivity:.4f} - 恶性肿瘤的检出率")
    print(f"   特异性 (Specificity): {specificity:.4f} - 良性肿瘤的识别率")
    print(f"   阳性预测值 (PPV): {ppv:.4f} - 预测为恶性的准确率")
    print(f"   阴性预测值 (NPV): {npv:.4f} - 预测为良性的准确率")
    
    # 特征重要性分析
    feature_importance = custom_mlp.get_feature_importance(X_test, y_test)
    
    # 创建特征重要性可视化
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6))
    
    # 最重要的15个特征
    top_15_idx = np.argsort(feature_importance)[-15:]
    top_15_features = [feature_names[i] for i in top_15_idx]
    top_15_scores = feature_importance[top_15_idx]
    
    ax1.barh(range(len(top_15_features)), top_15_scores)
    ax1.set_yticks(range(len(top_15_features)))
    ax1.set_yticklabels(top_15_features)
    ax1.set_xlabel('特征重要性分数')
    ax1.set_title('Top 15 最重要特征 (医疗诊断相关性)')
    ax1.grid(True, alpha=0.3)
    
    # 按特征类型分组的重要性
    feature_groups = {
        'radius': [name for name in feature_names if 'radius' in name],
        'texture': [name for name in feature_names if 'texture' in name],
        'perimeter': [name for name in feature_names if 'perimeter' in name],
        'area': [name for name in feature_names if 'area' in name],
        'smoothness': [name for name in feature_names if 'smoothness' in name],
        'compactness': [name for name in feature_names if 'compactness' in name],
        'concavity': [name for name in feature_names if 'concavity' in name],
        'concave_points': [name for name in feature_names if 'concave points' in name],
        'symmetry': [name for name in feature_names if 'symmetry' in name],
        'fractal_dimension': [name for name in feature_names if 'fractal_dimension' in name]
    }
    
    group_importance = {}
    for group_name, group_features in feature_groups.items():
        group_indices = [list(feature_names).index(fname) for fname in group_features if fname in feature_names]
        if group_indices:
            group_importance[group_name] = np.mean([feature_importance[i] for i in group_indices])
    
    groups = list(group_importance.keys())
    scores = list(group_importance.values())
    
    ax2.bar(groups, scores, color='skyblue', alpha=0.7)
    ax2.set_ylabel('平均特征重要性')
    ax2.set_title('按特征类型分组的重要性')
    ax2.tick_params(axis='x', rotation=45)
    ax2.grid(True, alpha=0.3)
    
    plt.tight_layout()
    
    # 保存医疗分析图表
    results_dir = "/root/code/ml/automl/examples/04_extending/01_classification_extension/results"
    plt.savefig(f"{results_dir}/medical_analysis.png", dpi=300, bbox_inches='tight')
    print(f"📁 医疗分析图表已保存到: {results_dir}/medical_analysis.png")
    
    plt.show()
    
    # 生成临床决策建议
    print(f"\n💡 临床决策建议:")
    if sensitivity >= 0.90:
        print("✅ 敏感性优秀，能够有效检出恶性肿瘤")
    elif sensitivity >= 0.80:
        print("⚠️ 敏感性良好，但建议结合其他检查手段")
    else:
        print("❌ 敏感性偏低，存在漏诊风险，需要改进模型")
    
    if specificity >= 0.85:
        print("✅ 特异性良好，假阳性率较低")
    else:
        print("⚠️ 特异性偏低，可能导致不必要的进一步检查")
    
    # 保存分析报告
    report_content = f"""
# 自定义MLP分类器医疗AI分析报告

## 生成时间
{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}

## 模型性能指标

### 医疗诊断关键指标
- 敏感性 (Sensitivity): {sensitivity:.4f}
- 特异性 (Specificity): {specificity:.4f}  
- 阳性预测值 (PPV): {ppv:.4f}
- 阴性预测值 (NPV): {npv:.4f}

### 机器学习指标
- 准确率: {sklearn.metrics.accuracy_score(y_test, y_pred):.4f}
- F1分数: {f1_score(y_test, y_pred, average='weighted'):.4f}
- AUC: {sklearn.metrics.roc_auc_score(y_test, y_proba[:, 1]):.4f}

## 特征重要性Top 10
"""
    
    for i, idx in enumerate(reversed(np.argsort(feature_importance)[-10:])):
        report_content += f"{i+1}. {feature_names[idx]}: {feature_importance[idx]:.4f}\n"
    
    report_content += f"""

## 临床应用建议

1. **模型部署**: 可作为乳腺癌诊断的辅助决策工具
2. **质量控制**: 建议与影像医师诊断结果进行对比验证
3. **持续改进**: 收集新的临床数据持续优化模型性能
4. **安全措施**: 低置信度预测应提醒医师人工复核

## 技术特点

- 网络架构: {custom_mlp.hidden_layer_depth}层隐藏层，每层{custom_mlp.num_nodes_per_layer}个神经元
- 激活函数: {custom_mlp.activation}
- 正则化: L2系数={custom_mlp.alpha}
- 优化器: {custom_mlp.solver}

---
*报告由自定义MLP分类器扩展示例自动生成*
"""
    
    with open(f"{results_dir}/medical_analysis_report.md", 'w', encoding='utf-8') as f:
        f.write(report_content)
    
    print(f"📄 完整医疗分析报告已保存到: {results_dir}/medical_analysis_report.md")


def main():
    """
    主函数：执行完整的自定义分类器扩展示例
    """
    print("🚀 Auto-sklearn自定义分类器扩展示例")
    print("=" * 60)
    
    try:
        # 1. 测试自定义组件基本功能
        custom_mlp, X_train, X_test, y_train, y_test = test_custom_component()
        
        # 2. 注册组件到Auto-sklearn并测试AutoML
        automl_result = register_and_test_automl()
        
        if automl_result is not None:
            automl_clf, X_train_automl, X_test_automl, y_train_automl, y_test_automl = automl_result
            
            # 3. 创建性能对比可视化
            create_performance_visualization(custom_mlp, automl_clf, X_test, y_test)
        
        # 4. 生成医疗AI专用分析报告
        feature_names = load_breast_cancer().feature_names
        create_medical_analysis_report(custom_mlp, X_test, y_test, feature_names)
        
        print("\n✅ 自定义分类器扩展示例执行完成!")
        print("📁 所有结果文件已保存到 results/ 目录")
        
        # 总结信息
        print(f"\n📊 示例总结:")
        print(f"   ✓ 成功创建自定义MLP分类器组件")
        print(f"   ✓ 实现完整的Auto-sklearn接口")
        print(f"   ✓ 注册到AutoML框架并成功运行")
        print(f"   ✓ 生成性能对比和医疗分析报告")
        print(f"   ✓ 为医疗AI应用提供专用分析功能")
        
    except Exception as e:
        print(f"\n❌ 示例执行过程中出现错误: {str(e)}")
        import traceback
        traceback.print_exc()


if __name__ == "__main__":
    main()